Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: stub for framework provider, mux, frameworking resource and datasource for metal_ssh_key #406

Merged
merged 16 commits into from
Feb 2, 2024

Conversation

t0mk
Copy link
Contributor

@t0mk t0mk commented Oct 10, 2023

This PR is a first step towards migration from TF SDKv2 to the plugin Framework. It's along way, and Hashicorp documents it at [0].

We want to have both types of providers exist in the repo until we can totally migrate to framework. We need to use "muxing" [1].

I base this on the continuous migration of the Linode TF provider [2]. [3] is a first PR where they introduced the framework provider and migrated token resource to the framework format.

For our case, I selected metal_ssh_key resource and datasource to migrate here, because those are simple resource types.

[0] https://developer.hashicorp.com/terraform/plugin/framework/migrating
[1] https://developer.hashicorp.com/terraform/plugin/framework/migrating/mux
[2] https://github.com/linode/terraform-provider-linode
[3] linode/terraform-provider-linode#791

Towards #365

@t0mk t0mk temporarily deployed to internal October 10, 2023 13:14 — with GitHub Actions Inactive
@t0mk
Copy link
Contributor Author

t0mk commented Oct 10, 2023

Thsi is a WIP. I wonder if there's a way not to have acceptance tests run on every commit.

@t0mk t0mk force-pushed the framework_migr_base_plus_ssh_key branch from 51065e9 to 47c48a3 Compare October 10, 2023 13:17
@t0mk t0mk temporarily deployed to internal October 10, 2023 13:17 — with GitHub Actions Inactive
@ocobles
Copy link
Contributor

ocobles commented Oct 11, 2023

Thsi is a WIP. I wonder if there's a way not to have acceptance tests run on every commit.

I think we can skip test execution for draft PRs. As I understand it, defining all required types in https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target without synchronize type, won't run the test till you change it to ready_for_review. A similar approach with more control could be adding the condition in the job, something like:

if: ${{ github.event_name == 'pull_request_target' && github.event.action == 'synchronize' && !github.event.pull_request.draft }}

Thoughts on this @ctreatma ?

@displague
Copy link
Member

I do have, from time to time, drafts where I want to run E2E tests. Perhaps a label (No E2E Testing) or the title (WIP or NOE2E) could signal this?

@ocobles
Copy link
Contributor

ocobles commented Oct 11, 2023

you can still run it manually since that condition is only for github.event_name == 'pull_request_target' and not for workflow_dispatch

@ctreatma
Copy link
Contributor

Yeah, @ocobles I think your suggestion is good. We should go with the second approach, adding a condition to the job (either by updating the authorize check or adding a separate check job before it). I don't think we should check for the synchronize action in the condition, though; if we want to limit the job to specific action names lets add that to the trigger config (synchronize and opened might be the only ones we really need?).

@t0mk t0mk temporarily deployed to internal October 16, 2023 12:42 — with GitHub Actions Inactive
@t0mk
Copy link
Contributor Author

t0mk commented Oct 16, 2023

I'm now doing the migration of the provider, and I also want to move resources and datasources to subdirectories, e.g equinix/metal_ssh_key/{resource,datasource}.go

The framework provider needs to refer to owned resource [0], and if we have resource in subdir, it needs to import the subdir (see top of framework_provider.go).

I run into issues with the fact that we have a lot of helper code straight in the github.com/equnix/terraform-provider-equinix/equinix namespace. The code of a resource, for example in equnix/metal_ssh_key/resource.go needs to import the Config struct which is in github.com/equnix/terraform-provider-equinix/equinix and since the provider is importing the subdir package, there's an import cycle.

I am not sure how to resolve it. The natural solution would be to move the config (and all the helpers that resources and Config are using) to equinix/internal. Then both provider and resource code could use them without cycles. But that is a huge change, affecting every reference to Config or the helper functions, and should be agreed with other contributors. Also I think it should be done separately from the migration work.

We need to break the cycle provider@equinix -> resource@equinix/metal_ssh_key/ -> config_struct,helpers@equinix

It could be done without breaking things, if we copy all the necessary code to equinix/internal/. Then, existing unrelated code will not have to be changed along the migration, but if there will be work done in parallel (to the migration) on helpers in original location, it will be hard to merge once we get rid of the SDKv2 resources.

I think the helpers and config must be moved to a subdir eventually if we want to have resource code in subdirs. Or is there another solution in Go that I can't see? My suggestion is to move the helpers and config first, and continue with migration later.

Also, it's important to do the move of the config and helpers properly, so that really all the functionality (and its dependencies) that resources need goes to a subdir. It should be done somehow aware of the framework provider and resources in subdir. Along with the move to internal/, we should move one existing SDKv2 resource to a subdir so that we are sure that we restructured things properly.

I need your feedback @ctreatma @displague .

Thanks for reading this.

[0] https://github.com/equinix/terraform-provider-equinix/blob/framework_migr_base_plus_ssh_key/equinix/framework_provider.go#L93

@displague
Copy link
Member

displague commented Oct 16, 2023

@t0mk have a look at #142. I was fairly far along in the refactoring of directories . The cyclical imports I was running into (and had yet to resolve) were in test mode.

I wanted to keep equinix/ for the public Provider (name?) object so that other projects that import Terraform Go providers could do so.

I moved all resources and "helpers" into internal/ with separate packages for each.

@t0mk
Copy link
Contributor Author

t0mk commented Oct 16, 2023

@displague I see, you moved everything but provider.go provider_test.go and equinix_sweeper_test.go from <repo_root>/equinix to <repo_root>/internal and structured it a lot in there. Is it possible you wouldn't run into the cycle in tests if you'd move it to <repo_root>/equinix/internal? That's how I see it in Linode TP.

Anyway, it looks like a way to go, and too bad you didn't manage to merge it last year.

I don't think we need to move all resources to subdirs at this point, since we will migrate them to framework plugin ecventually. We just need one as a tracing bullet, to see that most of the helper code is separated from equinix namespace.

Give me green light on the code move and I will do a PR, restructure it in a reasonable way, and then we will discuss the paths and directory structure there, as that's not too relevant to the migration.

@ctreatma
Copy link
Contributor

@t0mk, yes, you can go ahead with the code move. If you're looking for a resource / datasource to use as a testbed, the metal_ssh_key resource & datasource used here would be good candidates; step 1 would be refactoring within the SDKv2 implementation, and then step 2 would be migrating the refactored implementation to the plugin framework.

@t0mk
Copy link
Contributor Author

t0mk commented Oct 16, 2023

@ctreatma , great! I will do so. I was thinking about metal_ssh_key myself. Actually we don't even have a datasource for the user key.

@displague
Copy link
Member

My PR got too big too fast.
One piece that would be a nice chore that could be applied independently of resource moves and framework conversion is to move the helpers to various type specific packages.

@ocobles
Copy link
Contributor

ocobles commented Oct 17, 2023

Are there any disadvantages to moving into subfolders by service one level above the split by resource? I mean, internal/metal/ssh_key/ or internal/fabric/connection/. That approach keeps the main directory cleaner and helps limit the workspace for teams focused on a single service

@ocobles
Copy link
Contributor

ocobles commented Oct 17, 2023

Currently, we have a datasource for metal_project_ssh_key and resources for metal_project_ssh_key and metal_ssh_key. I see you have created a folder metal_ssh_key with both resource and datasource files. Is that datasource a new one to cover the GET user ssh key API request, or did you accidentally mix the resource for user ssh key and datasource for project ssh key?

@ocobles
Copy link
Contributor

ocobles commented Nov 22, 2023

Hi @t0mk, there are a few things I found while migrating resources that need to be addressed here:

  • While they coexist, both provider schemas must produce the same output. So if you add a description to max_retries or max_retry_wait_seconds make sure it is included also in the old sdkv2 provider schema
  • tfsdk struct tag doesn't have omitempty augmentation
  • id attribute must be defined in the resource schemas
  • A solution to add module to user agent:

//resource.go

func (r *Resource) Create(
	ctx context.Context,
	req resource.CreateRequest,
	resp *resource.CreateResponse,
) {

	r.Meta.AddFwModuleToMetalUserAgent(ctx, req.ProviderMeta)
	client := r.Meta.Metal

//config.go

func (c *Config) AddFwModuleToMetalUserAgent(ctx context.Context, meta tfsdk.Config) {
	c.Metal.UserAgent = generateFwModuleUserAgentString(ctx, meta, c.metalUserAgent)
}

func (c *Config) AddFwModuleToMetaGolUserAgent(ctx context.Context, meta tfsdk.Config) {
	c.Metalgo.GetConfig().UserAgent = generateFwModuleUserAgentString(ctx, meta, c.metalGoUserAgent)
}

func generateFwModuleUserAgentString(ctx context.Context, meta tfsdk.Config, baseUserAgent string) string {
	var m ProviderMeta
	diags := meta.Get(ctx, &m)
	if diags.HasError() {
		log.Printf("[WARN] error retrieving provider_meta")
		return baseUserAgent
	}
	if m.ModuleName != "" {
		return strings.Join([]string{m.ModuleName, baseUserAgent}, " ")
	}
	return baseUserAgent
}

@ocobles
Copy link
Contributor

ocobles commented Nov 22, 2023

more findings @t0mk :

import "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"

...

var UrlRE = regexp.MustCompile(`^https?://(?:www\.)?[a-zA-Z0-9./]+$`)

...

"endpoint": schema.StringAttribute{
  Optional:    true,
  Description: "The Equinix API base URL to point out desired environment. Defaults to " + config.DefaultBaseURL,
  Validators: []validator.String{
    stringvalidator.RegexMatches(urlRE, "must be a valid URL with http or https schema"),
  },
},

@displague displague mentioned this pull request Dec 6, 2023
@ocobles ocobles force-pushed the framework_migr_base_plus_ssh_key branch from 90f2213 to cf8930f Compare January 17, 2024 22:27
@ocobles
Copy link
Contributor

ocobles commented Jan 17, 2024

that go test error after my last commit is related to https://developer.hashicorp.com/terraform/plugin/testing/migrating#flag-redefined-panic

I'm going to open a different PR to fix the code before continuing with the work here. So basically we need to replace any resource.StateChangeConf references with helper/retry package

ocobles added a commit that referenced this pull request Jan 18, 2024
…#524)

Previous step to migrate testing functionality from
github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource to
github.com/hashicorp/terraform-plugin-testing/v2/helper/resource
required to add e2e tests to migrate from SDKv2 to Framework
#406 (comment)

Almost all resource.StateChangeConf references had already been
previously migrated to retry.StateChangeConf
@ocobles
Copy link
Contributor

ocobles commented Feb 1, 2024

go.work.sum Outdated Show resolved Hide resolved
Copy link
Contributor

@ctreatma ctreatma left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! I see all of the SSH key tests passing in CI (including the new upgrade test).

@ocobles ocobles merged commit 79bad91 into main Feb 2, 2024
4 of 5 checks passed
@ocobles ocobles deleted the framework_migr_base_plus_ssh_key branch February 2, 2024 18:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants